package com.meme.editor.model.sprite2d;

import org.apache.log4j.Logger;

import java.util.ListIterator;
import java.util.Vector;
import java.util.LinkedList;
import java.util.List;

import com.meme.editor.EntityObject;
import com.meme.editor.PropertyValueModification;
import com.meme.editor.PropertyValueModificationList;
import com.meme.editor.property.PropertyFactory;

public abstract class Tiled2dGrid extends ModuleGroup
{
	static Logger logger = Logger.getLogger (Tiled2dGrid.class);
	
	final static String GroupName_Tiled2dGridGroup   = "Tile Grid";
	final static String PropertyName_CellRows        = "Rows";
	final static String PropertyName_CellCols        = "Cols";
	final static String PropertyName_CellWidth       = "Cell Width";
	final static String PropertyName_CellHeight      = "Cell Height";
	
	
	int mCellWidth;
	int mCellHeight;
	int mCellRows;
	int mCellCols;
	
	public Tiled2dGrid (int cellWidth, int cellHeight, int cellRows, int cellCols)
	{
		createPropertyGroup (GroupName_Tiled2dGridGroup);
		createPublicProperty (GroupName_Tiled2dGridGroup, PropertyName_CellRows, PropertyFactory.ValueType_Number );;
		createPublicProperty (GroupName_Tiled2dGridGroup, PropertyName_CellCols, PropertyFactory.ValueType_Number );;
		createPublicProperty (GroupName_Tiled2dGridGroup, PropertyName_CellWidth, PropertyFactory.ValueType_Number );
		createPublicProperty (GroupName_Tiled2dGridGroup, PropertyName_CellHeight, PropertyFactory.ValueType_Number );

		
		setCellSize ( cellWidth > 1 ? cellWidth : 1, cellHeight > 1 ? cellHeight : 1 );
		setGridSize ( cellRows > 1  ? cellRows  : 1, cellCols   > 1 ? cellCols   : 1 );
		
	}
	
	
	@Override
	protected void _handleModifyingPropertyValues (PropertyValueModificationList modications)
	{		
		ListIterator<PropertyValueModification> iter = modications.listIterator();
		while ( iter.hasNext() )
		{
			PropertyValueModification mod = iter.next();
			
			if (   mod.mGroupName.equals (GroupName_Tiled2dGridGroup) )
			{
				if ( mod.mPropertyName.equals (PropertyName_CellRows) )
				{
					setGridSize (( (Float) (mod.mNewValue) ).intValue(), getCellCols ());
					iter.remove();
				}
				else if ( mod.mPropertyName.equals (PropertyName_CellCols) )
				{
					setGridSize (getCellRows (), ( (Float) (mod.mNewValue) ).intValue());
					iter.remove();
				}
				else if ( mod.mPropertyName.equals (PropertyName_CellWidth) )
				{
					setCellSize (( (Float) (mod.mNewValue) ).intValue(), getCellHeight ());
					iter.remove();
				}
				else if ( mod.mPropertyName.equals (PropertyName_CellHeight) )
				{
					setCellSize (getCellWidth (), ( (Float) (mod.mNewValue) ).intValue());
					iter.remove();
				}
			}
		}
			
		super._handleModifyingPropertyValues (modications);
	}	
	
	@Override
	public boolean isValidChild (EntityObject entity)
	{
		return entity instanceof Tiled2dModule;
	}
	
	public int getCellWidth  () 
	{
		return mCellWidth;
	}
	
	public int getCellHeight ()
	{
		return mCellHeight;
	}
	
	public int getCellRows   ()
	{
		return mCellRows;
	}
	
	public int getCellCols   ()
	{
		return mCellCols;
	}
	
	
	abstract int getMaxCellRows ();
	abstract int getMaxCellCols ();
	
	public boolean setCellSize (int cellWidth, int cellHeight)
	{
		logger.assertLog(cellWidth  > 0, "cellWidth can't be negative.");
		logger.assertLog(cellHeight > 0, "cellHeight can't be negative.");

		if ( ! (cellWidth > 0 && cellHeight > 0) )
			return false;
		
		mCellWidth = cellWidth;
		mCellHeight = cellHeight;
		
		changePublicPropertyValue ( GroupName_Tiled2dGridGroup, PropertyName_CellWidth, mCellWidth );
		changePublicPropertyValue ( GroupName_Tiled2dGridGroup, PropertyName_CellHeight, mCellHeight );
		
		return true;
	}
	
	public boolean setGridSize (int cellRows, int cellCols)
	{
		logger.assertLog(cellRows > 0 && cellRows <= getMaxCellRows (), "cellRows: out of range. cellRows=" + cellRows);
		logger.assertLog(cellCols > 0 && cellCols <= getMaxCellCols (), "cellCols: out of range. cellCols=" + cellCols);

		if ( ! (cellRows > 0 && cellRows <= getMaxCellRows () && cellCols > 0 && cellCols <= getMaxCellCols ()) )
			return false;	

		
		int oldRows = mCellRows;
		int oldCols = mCellCols;

		mCellRows = cellRows;
		mCellCols = cellCols;
		
		changePublicPropertyValue ( GroupName_Tiled2dGridGroup, PropertyName_CellRows, mCellRows );
		changePublicPropertyValue ( GroupName_Tiled2dGridGroup, PropertyName_CellCols, mCellCols );
		
		
		//----------------------------------------------------------------------
		// to change children list. Here, the route of changing children list 
		// is NOT standard. The standard route is very not efficient when handling
		// a large children list.
		//----------------------------------------------------------------------
		
		// _handleGridSizeChanged_StandardRoute (oldRows, oldCols);
		handleGridSizeChanged (oldRows, oldCols);

		return true;
	}
	
	protected abstract void handleGridSizeChanged (int oldRows, int oldCols);
}
